/** @jsxImportSource @emotion/react */
import { jsx, css, keyframes } from "@emotion/react";
import * as React from "react";
import PropTypes from "prop-types";
/*import { Text } from "./Text";
import { useTheme } from "./Theme/Providers";*/

import {
    useTheme, Text, VisuallyHidden,
} from "customize-easy-ui-component";


const spin = keyframes`
  to { 
    transform: rotate(360deg); 
  }
`;

const sizeStyles = {
  xs: css({ width: "1rem", height: "1rem" }),
  sm: css({ width: "3rem", height: "3rem" }),
  md: css({ width: "5rem", height: "5rem" }),
  lg: css({ width: "8rem", height: "8rem" }),
  xl: css({ width: "12rem", height: "12rem" })
};

interface SpinnerProps extends React.HTMLAttributes<HTMLDivElement> {
    /** The delay (in ms) before the spinner will appear
    * delay这段时间内，也没办法点击页面按钮的,也要同步等待后端的应答返回来，用户才能继续操作。
    *  */
    delay?: number;
    size?: "xs" | "sm" | "md" | "lg" | "xl";
    /** Attempt to center the spinner in the parent element */
    center?: boolean;
    /** Use an optional label */
    label?: string;
    //正在同步执行中,等待后端返回结果
    doing: boolean;
    //是否在左右轮播台右边半边的页面：针对在手机轮播台场景的需要：右半边和左半边分开显示的。
    carousel?: boolean;
}

// spinner css based on one provided by bootstrap
// https://getbootstrap.com/docs/4.3/components/spinners/
/** 替换LayerLoading功能；
 * 同步化处理 Spinner，
 * 执行操作不等待不可行啊，又不是查询，查询允许异步可以一块一块数据块的揭示出来，查询异步并发没伤害。
 *但是命令操作处理就不一样了，在后端应答之前，应当阻止用户操作， 防止业务逻辑混淆或错误。
 * 没有等待超时的机制？ 一直会等待；想要终止：用户主动得强制刷新URL，超过时间期限的操作无法撤销啊。
 * 假如用户强制刷新退出Spinner的，就无法保障后端服务器的操作结果能够正常通知用户了，一无所知了，用户只能主动查询了，新增加数据无法正常通知到位。
 *对比的是，异步模式用这个 <Suspense fallback={'Loading fallback...'}>  </Suspense>不用等待/可以并发的。
* */
export const Spinner: React.FunctionComponent<SpinnerProps> =
({
    delay = 400,
    size = "md",
    center=true,
    label,
    doing=false,
    carousel=false,
  ...other
}) => {
  const theme = useTheme();
  const [show, setShow] = React.useState(delay === 0 ? true : false);

  React.useEffect(() => {
    const timer = setTimeout(() => {
      setShow(true);
    }, delay);

    return () => {
      clearTimeout(timer);
    };
  }, [delay]);

  return (
    <div className="Spinner"
       css={{
           left: 0,
           bottom: 0,
           zIndex: theme.zIndices.waituntil,
           position: "absolute",
           top: 0,
           right: 0,
           borderRadius: theme.radii.lg,
           display: "flex",
           alignItems: "center",
           justifyContent: "center",
           background:  "rgba(255,255,255,0.7)",
           transition: "opacity 0.3s ease",
           pointerEvents: doing ? "auto" : "none",
           opacity: doing ? 1 : 0,
           //决定遮盖不能允许点击的范围, 手机两半页面左右轮播台需要匹配200vw遮盖。
           width: carousel? '200vw' : undefined,
           [theme.mediaQueries.md]: {
               left: "-30vw",
               width: "130vw",
               top: "-30vh",
               height: "130vh",
           },
           [theme.mediaQueries.lg]: {
               left: "-50vw",       //圈圈的可点击取消的遮盖层大小和位移 调整：由于Spinner嵌套在Dialog底下产生相对位置偏离问题。
               width: "150vw",
               top: "-50vh",
               height: "150vh",
           }
        }}
      {...other}
    >
      <div
        className="Spinner__sync"
        css={[
          {
            opacity: show ? 1 : 0,
            display: "inline-block",
            transition: "opacity 0.4s cubic-bezier(0.35,0,0.25,1)"
          },
          center && {
            left:  carousel? '100vw' : 0,      //遮盖背后按钮防止被点击触发
            bottom: 0,
            width: "100%",
            height: "100%",
            boxSizing: "border-box",
            display: "flex",
            alignItems: "center",
            alignSelf: "center",
            justifyContent: "center",
            position: "fixed"
          }
        ]}
      >
        <div
          className="Spinner__container"
          role="status"
          css={{
            color: theme.colors.text.default,
            textAlign: "center",
            display: "inline-block",
            margin: 'auto'
          }}
        >
          <div
            className="Spinner__spinner"
            css={[
              css`
                display: inline-block;
                vertical-align: text-bottom;
                border: 0.15em solid currentColor;
                border-right-color: transparent;
                border-radius: 50%;
                animation: ${spin} 0.75s linear infinite;
              `,
              sizeStyles[size]
            ]}
          />
          {label ? (
            <Text
              className="Spinner__label"
              wrap={false}
              css={{ display: "block", marginTop: theme.spaces.sm }}
              variant="subtitle"
            >
              {label}
            </Text>
          ) : (
            <VisuallyHidden>{"Loading"}</VisuallyHidden>
          )}
        </div>
      </div>
    </div>
  );
};

Spinner.propTypes = {
  delay: PropTypes.number,
  center: PropTypes.bool,
  label: PropTypes.string,
  size: PropTypes.oneOf(["xs", "sm", "md", "lg", "xl"])
};
